import {
  Inject,
  Injectable,
  LoggerService as LoggerServiceInterface, Scope,
} from '@nestjs/common';
import dayjs from 'dayjs';
import { createLogger, format, Logger, transports } from 'winston';
import {INQUIRER} from "@nestjs/core";
import {globalAsyncLocalStorage} from "../utils/utils";

const { combine, timestamp, printf } = format;

@Injectable({ scope: Scope.TRANSIENT })
export class LoggerService implements LoggerServiceInterface {
  logger: Logger;
  context: string;

  constructor(@Inject(INQUIRER) source?: string | object) {
    this.context = typeof source === 'string' ? source : source?.constructor?.name ?? '';

    const IS_PRODUCTION = process.env.NODE_ENV === 'prod';

    this.logger = createLogger({
      // 日志格式化为"2001-01-01 00:00:00 [3612] [INFO] [NestApplication] Nest application successfully started"
      format: combine(
        timestamp(),
        printf((info) => {
          const { timestamp, level, message } = info;
          const store = globalAsyncLocalStorage.getStore();
          const SPLAT = info[Symbol.for('splat') as unknown as keyof typeof info];
          // @ts-ignore
          const context = SPLAT?.[0] ?? 'Undefined';
          // @ts-ignore
          return `${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')} [${
            process.pid
          }] [${store?.requestId ?? 'JOB'}] [${level.toUpperCase()}] [${context}] ${message instanceof Object ? JSON.stringify(message, null ,4) : message}`;
        }),
      ),
      transports: [
        new transports.Console({
          level: IS_PRODUCTION ? 'info' : 'debug',
        }),
      ],
    });
  }

  debug(message: any, context?: string) {
    this.logger.debug(message, context ?? this.context);
  }

  log(message: any, context?: string) {
    this.logger.info(message, context ?? this.context);
  }

  info(message: any, context?: string) {
    this.logger.info(message, context ?? this.context);
  }

  warn(message: any, context?: string) {
    this.logger.warn(message, context ?? this.context);
  }

  error(message: any, context?: string) {
    this.logger.error(message, context ?? this.context);
  }
}
